<template>
    <div>
      <!-- 预览文章分类 -->
      <el-card class="box-card">
        <div slot="header" class="clearfix header-box">
          <span>文章分类</span>
          <el-button type="primary" size="mini" @click="addCateShowDialogBtnFn">添加分类</el-button>
        </div>
        <!-- 分类数据表格 -->
        <el-table :data="cateList" style="width: 100%" border stripe>
          <!-- type是table-column内置属性，type值为index，意思就是第一个单元格用索引值 -->
           <el-table-column type="index" label="序号" width="100"></el-table-column>
           <!-- prop属性决定当前table-column标签显示的属性，如下的table-column的prop属性值为cate_name，那么这个table-column就会显示cate_name变量值 -->
           <el-table-column prop="cate_name" label="分类名称"></el-table-column>
           <el-table-column prop="cate_alias" label="分类别名"></el-table-column>
           <el-table-column label="操作">
            <!-- 以下用template标签将两个input标签包裹住是想使用作用域插槽 -->
             <template v-slot="scope">
              <el-button type="primary" size="mini" @click="updateCateBtnFn(scope.row)">修改</el-button>
              <el-button type="danger" size="mini" @click="delCateFn(scope.row)">删除</el-button>
             </template>
           </el-table-column>
         </el-table>
      </el-card>

      <!-- 添加文章分类的对话框 -->
      <!--
          el-dialog 对话框组件
            title：左上角标题
            visible：控制对话框是否显示
            visible.sync：当组件内检测到对话框关闭时，它就会回传false给vue变量
            .sync类似于v-model，可以给子组件实现双向数据绑定，不过在vue2中一个标签只能用一次v-model，而sync可以用多次，不过在vue3中被移除了
            close是el-dialog组件提供的事件，当el-dialog被关闭时就会被触发
       -->
      <el-dialog
        title="提示"
        :visible.sync="dialogVisible"
        width="30%"
        @close="dialogCloseFn">
        <el-form :model="addForm" :rules="addRules" ref="addRef" label-width="80px">
          <el-form-item label="分类名称" prop="cate_name">
            <el-input v-model="addForm.cate_name" minlength="1" maxlength="10"></el-input>
          </el-form-item>
          <el-form-item label="分类别名" prop="cate_alias">
            <el-input v-model="addForm.cate_alias" minlength="1" maxlength="15"></el-input>
          </el-form-item>
        </el-form>
        <span slot="footer" class="dialog-footer">
          <el-button @click="cancelFn">取 消</el-button>
          <el-button type="primary" @click="confirmFn">确 定</el-button>
        </span>
      </el-dialog>
    </div>
  </template>

<script>
import { getArtCateListAPI, saveArtCateAPI, updateArtCateAPI, delArtCateAPI } from '@/api'
export default {
  name: 'ArtCate',
  data () {
    return {
      cateList: [], // 这个数组用来保存文章分类
      dialogVisible: false, // 这个是elementUI中组件的配置，负责文章分类对话框的显示(true)和隐藏(false)
      addForm: { // 添加表单的数据对象
        cate_name: '',
        cate_alias: ''
      },
      addRules: { // 添加表单的验证规则对象
        cate_name: [
          { required: true, message: '请输入分类名称', trigger: 'blur' },
          { pattern: /^\S{1,10}$/, message: '分类名必须是1-10位的非空字符', trigger: 'blur' }
        ],
        cate_alias: [
          { required: true, message: '请输入分类别名', trigger: 'blur' },
          { pattern: /^[a-zA-Z0-9]{1,15}$/, message: '分类别名必须是1-15位的字母数字', trigger: 'blur' }
        ]
      },
      isEdit: false, // true代表着编辑状态，false代表着新增状态
      editId: '' // 保存正在被编辑的数据的id值
    }
  },
  created () {
    // 获取文章分类的列表
    this.getArtCateFn()
  },
  methods: {
    // 获取文章分类的列表
    async getArtCateFn () {
      const res = await getArtCateListAPI()
      this.cateList = res.data.data
    },
    // 添加分类按钮的点击事件，为了让对话框出现
    addCateShowDialogBtnFn () {
      this.isEdit = false // 告诉组件触发对话框的是添加分类按钮
      this.editId = ''
      this.dialogVisible = true
    },
    // 对话框中取消按钮的点击事件，让对话框消失
    cancelFn () {
      this.dialogVisible = false
    },
    // 对话框中确认按钮的点击事件，让对话框消失/调用保存文章分类的接口
    confirmFn () {
      // 点击确认后，将两个输入框的值输入到后台进行校验
      this.$refs.addRef.validate(async valid => {
        if (valid) {
          if (this.isEdit) { // 当这个判断成立，证明用户点击的是修改按钮(因为此时isEdit的值为true，它是给修改按钮设置的标识符)，那么就调用修改的接口
            const { data: res } = await updateArtCateAPI({ id: this.editId, ...this.addForm })
            if (res.code !== 0) return this.$message.error('更新分类失败！')
            this.$message.success('更新分类成功！')
          } else { // 这里是当isEdit为false时，它是添加分类的标识，所以就调用添加分类的接口
            // 通过校验后调用指定接口，并且将输入框中的值addForm，作为参数传递给接口方法，让其将addForm传到后台
            const { data: res } = await saveArtCateAPI(this.addForm)
            if (res.code !== 0) return this.$message.error(res.message)
            this.$message.success(res.message)
          }

          // 再重新请求一次文章列表，拿到最新的数据，让表格更新
          this.getArtCateFn()
          // 让对话框消失
          this.dialogVisible = false
        } else {
          return false
        }
      })
    },
    // 对话框被关闭时的回调
    dialogCloseFn () {
      // 以下实现的效果是，当对话框已关闭，对话框中两个输入框的值清空，避免下一次打开对话框的时候，输入框还残留着上一次的内容
      this.$refs.addRef.resetFields() // 通过ref属性拿到对话框中的两个输入框，再利用组件内置的resetFields方法将两个输入框中的值恢复到最初始的值(空值)
    },
    // 修改分类按钮的点击事件
    updateCateBtnFn (obj) { // obj接收的是scope.row
      this.isEdit = true // 因为修改按钮和添加分类按钮共用一个对话框，所以为了辨别对话框是哪个按钮触发的，这里用isEdit来做标识，当idEdit为true时，说明是修改按钮触发的，为false时，是添加分类按钮触发的
      this.editId = obj.id
      this.dialogVisible = true // 令对话框显示
      // 数据回显，让当前点击的按钮所在的那一行中的相关数据重新显示在对话框中的两个输入框中
      this.$nextTick(() => { // 这个$nextTick可以等到真实dom更新后再执行，这里是先让对话框显示，对话框中有两个输入框就跟着先显示了，然后执行nextTick中的代码，重新给两个输入框双向绑定的数据赋值，重新使得两个输入框中有新的值，这样会使得这两个输入框的最初始值为空值，从而后面要使用resetFields()将这两个输入框中的值恢复到最初始的值的时候是空值
        this.addForm.cate_name = obj.cate_name
        this.addForm.cate_alias = obj.cate_alias
      })
    },
    // 删除分类按钮的点击事件
    async delCateFn (obj) {
      const { data: res } = await delArtCateAPI(obj.id)
      if (res.code !== 0) return this.$message.error(res.message)
      this.$message.success(res.message)
      // 再重新请求一次文章列表，拿到最新的数据，让表格更新
      this.getArtCateFn()
    }
  }
}
</script>

  <style lang="less" scoped>
  .header-box {
    display: flex;
    justify-content: space-between;
    align-items: center;
  }
  </style>
